#pragma once

#include <boost/unordered_map.hpp>
#include <boost/shared_ptr.hpp>

#include <engine.core/noncopyable.hpp>

#include "exports.hpp"
#include "Component.hpp"
#include "Object.hpp"




namespace Engine
{
	namespace Entity
	{
		/**
		 * A ComponentSystem handles all components of the same type, ie. all components
		 * that return the same id.
		 *
		 * This is the base class for components that do not require a logic update each frame.
		 * For components that require subsequent updates, please see UpdatableComponentSystem.
		 */
		class ENGINE_ENTITY_API ComponentSystem
			: public noncopyable
		{
		public:

			typedef boost::shared_ptr<ComponentSystem>   ptr;

			ComponentSystem();
			virtual ~ComponentSystem();



			/**
			 * Tests if this ComponentSystem requires a call to update each frame.
			 * The default implementation returns false.
			 */
			virtual bool requiresUpdate() const;

			/**
			 * Sets if the system requires an update.
			 */
			virtual void setRequiresUpdate(bool requires);

			/**
			 * Updates all components that belong to this ComponentSystem.
			 * Only updates components when requiresUpdate() returns true.
			 * Does nothing otherwise.
			 */
			virtual void update();



			/**
			 * @returns the component attached to the given entity
			 * @returns nullptr in case there is no component
			 */
			Component::ptr component(Entity::Object* entity) const;



			/**
			 * Attaches the given component to the given entity.
			 *
			 * This system will store both the entity AND the component pointer, however
			 * it does not take ownership of the entity.
			 *
			 * @param entity       the entity to attach the component to
			 * @param component    the component to store
			 * @param components   the components required by the given component
			 */
			bool attach(Entity::Object* entity, Component::ptr component, const Component::map& components);

			/**
			 * Detaches the given component to the given entity.
			 */
			bool detach(Entity::Object* entity);

		protected:

			typedef boost::unordered_map<Object*, Component::ptr>   Components;

			bool         m_requiresUpdate;
			Components   m_components;
		};
		///////////////////////////////////////////////////////////////////////////////////////////
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
